package adke.managers;

import adke.Util;
import adke.gui.animations.ParticleAnimation;
import adke.gui.animations.TextAnimation;
import adke.gui.panels.GFXPanel;
import adke.gui.panels.GFXPanel2;
import adke.gui.panels.GamePanel;
import adke.gui.panels.LinePanel;
import adke.listeners.GameListener;
import adke.listeners.PlayerListener;
import adke.models.DropPolicy;
import adke.models.LinePanelBorder;
import adke.models.Player;
import adke.models.policies.RandomTimedPolicy;
import adke.models.policies.StandardPolicy;
import adke.models.powerups.Powerup;
import java.awt.Color;
import java.util.Timer;
import java.util.Vector;

// zorgt ervoor dat er powerups vallen in het speelveld
// kijkt wanneer dit geschikt zou uitkomen, en waar
// de powerup dan het best geplaatst zou kunnen worden

// houd gameevents bij
// houd playerevents bij
public class DropManager implements GameListener, PlayerListener
{
    private static Vector<DropPolicy> ENABLED_POLICIES;
    
    // policies die gebruikt kunnen worden om te bepalen wat het drop-gedrag moet zijn
    // we kunnen policies combineren, of doordraaien met enkelen
    
    // POLICIES OVER POLICIES
    
    // mix random policies
    public final static int POLICY_MIX_RANDOM_POLICIES = -1;
    
    // werk alle policies in een rijtje af (beginnend bij een random)
    public final static int POLICY_POLICIES_IN_ORDER = -2;
    
    // GEWONE POLICIES
    
    // als een speler sterft worden de eigenschappen (powerups) gedropt
    public final static int POLICY_DROP_WHEN_DEAD = 0;
    
    // drop met random intervallen random powerups
    public final static int POLICY_DROP_RANDOM_TIMED = 1;
    
    // laat spelers met random powerups beginnen (property)
    public final static int POLICY_PLAYERS_BEGIN_WITH_POWERUP = 2;
    
    // geef een speler een random powerup als hij een speler gedood heeft
    public final static int POLICY_GIVE_ON_KILL = 3;
    
    // drop een ranodm powerup als er iemand gedood wordt (dus niet sterft aan zichzelf of muur)
    public final static int POLICY_DROP_ON_KILL = 4;
    
    // drop powerups in een bepaalde volgorde, bijvoorbeeld dat elke minstens
    // een keer gedropt wordt
    public final static int POLICY_DROP_IN_ORDER = 5;
    
    // drop een powerup als er een powerup gebruikt wordt
    public final static int POLICY_DROP_ON_USE = 6;
    
    // drop een powerup als er een bepaalde score wordt gehaald, of als er een
    // bepaald verschil ontstaat tussen scores
    public final static int POLICY_DROP_ON_SCORE = 7;
    
    // drop een powerup als iemand door een gat gaat
    public final static int POLICY_DROP_ON_CROSS = 8;
    
    // powerups die in het veld liggen
    private static Vector<Powerup> DROPPED_POWERUPS;
    
    public DropManager()
    {
        ENABLED_POLICIES = new Vector();
        DROPPED_POWERUPS = new Vector();
        
        // TODO: customizable
        setDropPolicy(POLICY_DROP_RANDOM_TIMED);
        
        // register listeners
        GameManager.addListener(this);
        PlayerManager.addListener(this);
    }
    
    private static DropPolicy getDropPolicy(int dropPolicy)
    {
        switch (dropPolicy)
        {
            case POLICY_DROP_RANDOM_TIMED:
            {
                return new RandomTimedPolicy(dropPolicy);
            }
            
            default:
            {
                return new StandardPolicy(dropPolicy);
            }
        }
    }
    
    public static void setDropPolicy(int dropPolicy)
    {
        ENABLED_POLICIES.clear();
        ENABLED_POLICIES.add(getDropPolicy(dropPolicy));
    }

    public static void addDropPolicy(int dropPolicy)
    {
        DropPolicy policy = getDropPolicy(dropPolicy);
        
        // check of hij niet al bestaat
        if (!ENABLED_POLICIES.contains(policy))
            ENABLED_POLICIES.add(policy);
    }
    
    public static boolean isPolicyEnabled(int dropPolicy)
    {
        return ENABLED_POLICIES.contains(getDropPolicy(dropPolicy));
    }
    
    public static DropPolicy getEnabledPolicy(int policy)
    {   
        for (DropPolicy dp : ENABLED_POLICIES)
        {
            if (dp.getID() == policy)
                return dp;
        }
        
        return null;
    }
    
    public static void dropPowerup(Powerup powerup)
    {        
        if (powerup == null) return;
        
        // random locatie
        int w = GamePanel.getInstance().getGameWidth();
        int h = GamePanel.getInstance().getGameHeight();
        
        int x = -1; int y = -1;
        
        boolean goodSpot = false;
        int tries = 0;
        
        // doe 5 pogingen een goede spot te vinden
        while (!goodSpot && tries < 5)
        {
            x = Util.random(w); y = Util.random(h);

            // afstand tot de grens (die kan verschuiven)
            int BD = LinePanelBorder.getInstance().getHighestOffset();
            
            // zorg dat we binnen de grenzen vallen
            if (x < BD) x = BD;
            if (y < BD) y = BD;
            if (x > w - BD) x = w - BD;
            if (y > h - BD) y = h - BD;
            
            // valideer locatie
            goodSpot = LinePanel.getInstance().validateDropSpot(x, y);
            
            tries++;
        }
        
        // droppoging gefaald
        if (tries >= 5) 
        {
            System.out.println("Couldn't find a suitable location for powerup");
            return;
        }
        
        powerup.setLocation(x, y);
        
        System.out.println(Util.getLogTimeString(GameManager.getGameTime()) + 
                "Dropping powerup: " + powerup + " (" + powerup.getX() + "," + powerup.getY() + ")");
        
        DROPPED_POWERUPS.add(powerup);
        
        // notify listeners
        GamePowerupManager.powerupDropped(powerup);
    }
    
    // gaan we over ene powerup heen?
    public static boolean pickingUpPowerup(int x, int y)
    {
        for (Powerup p : DROPPED_POWERUPS)
        {
            // als dit de powerup is die we zoeken
            if (p.isOnLocation(x, y))
            {
                return true;
            }
        }
        
        return false;
    }
    
    // pak ene powerup op als we eroverheen gaan
    public static Powerup pickUpPowerup(int x, int y)
    {
        Powerup p;
        
        for (int i = 0; i < DROPPED_POWERUPS.size(); i++)
        {
            p = DROPPED_POWERUPS.get(i);
            
            // als dit de powerup is die we zoeken
            if (p.isOnLocation(x, y))
            {
                DROPPED_POWERUPS.remove(i);
                DROPPED_POWERUPS.trimToSize();
                
                // TODO: alleen powerup wegpainten die we gepakt hebben
                GFXPanel2.getInstance().reset();
                
                // TODO: laten werken met listeners
                // laat animatie zien om aan te geven welke powerup we gepakt hebben
                //AnimationManager.queueAnimation(new TextFlash("TEST", 100, 100), 100);
                //AnimationManager.queueAnimationOnce(new ParticleAnimation(PlayerManager.getPlayer(Color.RED)));
                
                // hier wordt niet meteen genotified naar de listeners
                // dit is omdat de powerup hier nog niet weet wie de eigenaar wordt
                // dit kan nadelig uitpakken als de listeners dat dan nog niet te weten kunnen komen
                
                return p;
            }
        }
        
        return null;
    }
    
    public static Powerup[] getDroppedPowerups()
    {
        return DROPPED_POWERUPS.toArray(new Powerup[DROPPED_POWERUPS.size()]);
    }
    
    public static int getDroppedPowerupCount()
    {
        return DROPPED_POWERUPS.size();
    }
    
    // bij de volgende implementaties hoeft niet elke keer elke policy geactivate te worden
    // omdat niet elke policy voor elke situatie is
    
    // door GameListener
    
    public void gameStarted()
    {
        
    }

    public void gameEnded()
    {
    }

    public void roundStarted()
    {
        DROPPED_POWERUPS.clear();
        
        // policy 1: drop met random intervallen random powerups
        if (isPolicyEnabled(POLICY_DROP_RANDOM_TIMED))
        {
            getEnabledPolicy(POLICY_DROP_RANDOM_TIMED).startPolicy();
        }
    }

    public void roundEnded()
    {
        // policy 1: drop met random intervallen random powerups
        if (isPolicyEnabled(POLICY_DROP_RANDOM_TIMED))
        {
            // stop met het droppen van powerups
            getEnabledPolicy(POLICY_DROP_RANDOM_TIMED).stopPolicy();
        }
    }

    // door PlayerListener
    
    public void playerDied(Player deadPlayer)
    {
    }

    public void playerKilledPlayer(Player killer, Player victim)
    {
    }
}
